package service

import (
	"archive/zip"
	"bytes"
	"fmt"
	"myApp/model"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"gorm.io/gorm"
)

type GetServiceRequest struct {
	CustId    *string  `json:"custId"`
	Mobile    *string  `json:"mobile"`
	SendLimit *int64   `json:"sendLimit" validate:"gte:0"`
	PushRatio *float64 `json:"pushRatio" validate:"gte:0,lte:100"`
	RiskRatio *float64 `json:"riskRatio" validate:"gte:0,lte:100"`
}

type GetServiceResponse struct {
	model.CustInfo
	SendNum int64 `json:"sendNum"`
}

type ExportServiceRequest struct {
	SendLimit      *int64   `json:"sendLimit" validate:"gte:0"`
	PushRatio      *float64 `json:"pushRatio" validate:"gte:0,lte:100"`
	RiskRatio      *float64 `json:"riskRatio" validate:"gte:0,lte:100"`
	ProvFilterType *string  `json:"provFilterType"`
	Province       *string  `json:"province"` // 省份字段为字符串类型
}

type ExportServiceResponse struct {
	Url string `json:"url"`
}

func GetService(request *GetServiceRequest) (*GetServiceResponse, error) {
	response := &GetServiceResponse{}
	if request.CustId != nil {
		response.CustInfo.CustId = *request.CustId
	}
	if request.Mobile != nil {
		response.CustInfo.Mobile = *request.Mobile
	}
	err := model.DB.Transaction(func(tx *gorm.DB) error {
		var err error
		// 获取信息
		err = model.GetInfo(tx, &response.CustInfo)
		if err != nil {
			return err
		}

		// 判断是否满足条件
		if (response.PushRatio != nil && request.PushRatio != nil && *response.PushRatio*100 < *request.PushRatio) ||
			(response.RiskRatio != nil && request.RiskRatio != nil && *response.RiskRatio*100 > *request.RiskRatio) {
			response = nil
			return nil
		}
		// 查询具体用户营销次数
		times, err := model.GetSendCnt(tx, response.CustId)
		if err != nil {
			return err
		}
		response.SendNum = times
		if request.SendLimit != nil && times >= *request.SendLimit {
			response = nil
			return nil
		}
		// 增加记录
		err = model.AddRecord(tx, response.CustId)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return response, nil
}

func ExportService(request *ExportServiceRequest) (*ExportServiceResponse, error) {
	response := &ExportServiceResponse{}
	var result []string
	// 先查询info表 满足条件的ids
	err := model.DB.Transaction(func(tx *gorm.DB) error {
		var err error
		var custIDs []string
		// 构建查询条件
		var conditions []interface{}
		query := ""

		if request.PushRatio != nil {
			query += "(push_ratio >= ? OR push_ratio IS NULL) AND "
			conditions = append(conditions, *request.PushRatio/100)
		}
		if request.RiskRatio != nil {
			query += "(risk_ratio <= ? OR risk_ratio IS NULL) AND "
			conditions = append(conditions, *request.RiskRatio/100)
		}
		if request.ProvFilterType != nil && request.Province != nil {
			provinces := strings.Split(*request.Province, ",")
			if *request.ProvFilterType == "include" {
				query += "province IN (?) AND "
				conditions = append(conditions, provinces)
			} else if *request.ProvFilterType == "exclude" {
				query += "province NOT IN (?) AND "
				conditions = append(conditions, provinces)
			}
		}
		// 移除最后一个 "AND "
		if len(query) > 0 {
			query = query[:len(query)-4]
		}

		err = model.GetAllCustInfoByCondition(tx, &custIDs, query, conditions)
		if err != nil {
			return err
		}

		excludeIDs := make([]string, 0)
		idCntMap := make(map[string]int64)
		curDate := time.Now()
		// 先查今天的并保存到map里
		tmpList := make([]model.CustomerCount, 0)
		//err = model.GetCntByDate(tx, &tmpList, curDate)
		//if err != nil {
		//	return err
		//}
		//for _, t := range tmpList {
		//	idCntMap[t.CustId] += t.Count
		//}

		for day := 0; day <= 30; day++ {
			err = model.GetCnt(tx, &tmpList, curDate.AddDate(0, 0, -1*day))
			if err != nil {
				return err
			}
			for _, t := range tmpList {
				idCntMap[t.CustId] += t.Count
			}
		}
		if request.SendLimit != nil {
			for key, val := range idCntMap {
				if val >= *request.SendLimit {
					excludeIDs = append(excludeIDs, key)
				}
			}
		}

		result = removeElements(custIDs, excludeIDs)
		return nil
	})
	if err != nil {
		return nil, err
	}

	sort.Slice(result, func(i, j int) bool {
		return result[i] < result[j]
	})

	// 使用 bytes.Buffer 代替文件写入，减少磁盘I/O
	var buffer bytes.Buffer

	for _, custID := range result {
		_, err := buffer.WriteString(fmt.Sprintf("%s\n", custID)) // 将客户ID写入缓冲区
		if err != nil {
			return nil, err // 错误处理
		}
	}

	// 创建临时ZIP文件
	downloadDir := "/tmp/download"
	zipFileName := filepath.Join(downloadDir, "customers.zip")
	zipFile, err := os.Create(zipFileName) // 创建ZIP文件
	if err != nil {
		return nil, err // 如果创建ZIP文件失败，返回错误
	}
	defer zipFile.Close() // 确保ZIP文件在函数结束时关闭

	zipWriter := zip.NewWriter(zipFile) // 创建ZIP写入器
	defer zipWriter.Close()             // 确保ZIP写入器在函数结束时关闭

	// 在ZIP文件中创建一个新的条目，并将缓冲区数据写入其中
	w, err := zipWriter.Create("customers.txt")
	if err != nil {
		return nil, err // 如果创建条目失败，返回错误
	}

	_, err = w.Write(buffer.Bytes()) // 将缓冲区的数据写入ZIP条目
	if err != nil {
		return nil, err // 如果写入过程中发生错误，返回错误
	}

	// 返回zip文件的URL
	response.Url = fmt.Sprintf("%s", "/download/customers.zip") // 构建ZIP文件的URL
	return response, nil                                        // 返回包含URL的响应对象
}

func removeElements(a, b []string) []string {
	m := make(map[string]bool)
	// 将b切片中的所有元素添加到map中，用于快速查找
	for _, item := range b {
		m[item] = true
	}

	var result []string // 用于存储结果
	for _, item := range a {
		if _, found := m[item]; !found {
			// 如果item不在map中，则添加到结果切片中
			result = append(result, item)
		}
	}
	return result
}
